/**
 *  学习目标：Todos案例
 *  需求1✅：组件拆分
 *  需求2✅：渲染任务列表
 *  需求3✅：根据id更新一条任务
 *  需求4✅：根据id删除一条数据功能
 *  需求5✅：点谁谁有边框-数据驱动
 *  需求6✅：点谁谁有边框-实现点击修改type
 *  需求7✅：数据切换-🗝️计算属性
 *  需求8✅：清除已完成
 *  需求9✅：统计未完成的任务数量
 *  需求10✅：Header改造受控组件
 *  需求11✅：监听回车事件，数据新增到列表中
 *  需求12✅：新增数据-细节优化
 *  需求13✅：数据缓存
 *  需求14✅：小选影响全选
 *  需求15✅：全选影响小选
 */
import React from 'react';
import './styles/base.css';
import './styles/index.css';

export default class App extends React.Component {
  // 2.1 声明state.list为一个数组，并且设置初始值
  state = {
    // 5.1 声明state.type 表示当前选中的状态，
    // 默认值给一个all，type的值只能是all  active  completed
    // 13.3 从缓存中取出数据，作为初始值，💥将list转为数组
    // 13.4 🔔注意缓存可能被删除，使用"逻辑或"来设置空的初始值
    type: localStorage.getItem('todo-type') || 'all',
    list: JSON.parse(localStorage.getItem('todo-list')) || [],
  };

  // 13.1 🗝️使用componentDidUpdate监听数据变化，获取到更新后的数据
  componentDidUpdate() {
    const { list, type } = this.state;
    console.log('数据更新了，最新的数据是  ----->  ', type, list);
    // 13.2 将数据保存到本地缓存中， 💥 注意转为string
    localStorage.setItem('todo-list', JSON.stringify(list));
    localStorage.setItem('todo-type', type);
  }

  //   15.1 App中定义全选的回调函数
  handleCheckAll = (e) => {
    console.log('come here checked  ----->  ', e.target.checked);
    const { list } = this.state;
    const newList = list.map((item) => {
      return {
        ...item,
        isDone: e.target.checked,
      };
    });

    console.log('newList  ----->  ', newList);
    // 15.4 完成全选的计算逻辑
    this.setState({ list: newList });
  };

  // 11.1 App中定义新增的回调函数
  handleAdd = (task) => {
    console.log('come here  ----->  ', task);
    // 11.5 完成新增的逻辑
    this.setState({ list: [{ id: Date.now(), task, isDone: false }, ...this.state.list] });
  };

  //   8.1 在App中定义清除的回调函数
  handleClearDone = () => {
    //  sst
    const { list } = this.state;
    // 8.4 完成清除的逻辑
    const newList = list.filter((item) => !item.isDone);
    this.setState({ list: newList });
  };

  //   6.1 App中定义修改type的回调函数
  handleUpdateType = (type) => {
    // 6.4 完成修改type的逻辑
    this.setState({ type });
  };

  //   4.1  App中定义一个删除一条数据的回调函数
  handleDelById = (id) => {
    // 4.4 完成删除的逻辑
    const { list } = this.state;
    const newList = list.filter((item) => {
      return item.id !== id;
    });
    this.setState({ list: newList });
  };

  // 3.1 App中定义一个修改list的回调函数
  handleUpdateById = (id) => {
    // 3.4 回到回调函数中，完成更新的计算逻辑

    const { list } = this.state;
    const newList = list.map((item) => {
      return {
        // 把原本的对象，复制所有的键值对
        ...item,
        // 对为id的isDone取反
        isDone: item.id === id ? !item.isDone : item.isDone,
      };
    });

    // 🗝️ 关键步骤
    this.setState({
      list: newList,
    });
  };

  render() {
    const { list, type } = this.state;

    // setState -> 导致数据发生变化 -> render重新执行
    // 🗝️React模拟计算属性：render中return同级，每次数据变化，计算属性会自动计算
    // 7.1 定义一个计算属性showList
    const showList = list.filter((item) => {
      // 如果type为active，返回item.isDone为false的
      if (type === 'active') return !item.isDone;

      // 如果type为compelted，返回item.isDone为true的
      if (type === 'completed') return item.isDone;

      // 如果type为all， 返回true，表示全部都要
      return true;
    });

    //  14.1 App中定义一个计算属性isAll，通过计算每个小框的isDone是否为true，得到布尔值
    // 如果所有的isDone都为true，那么isAll为true，
    // 如果有一个isDone都为false，那么isAll为false

    // 14.4 💥every当数组为空时，要加判断条件
    const isAll = !list.length
      ? false
      : list.every((item) => {
          return item.isDone;
        });

    return (
      <section className="todoapp">
        {/* 头部 */}
        <Header
          // 11.2 通过子传父技术，将回调传给Header组价
          handleAdd={this.handleAdd}
        ></Header>
        {/* 主体 */}
        {/* 2.2 通过父传子技术，将list传给Main组件 */}
        <Main
          // 7.2 将showList，传给Main组件的props.list
          list={showList}
          // 3.2 通过子传父技术，将回调函数传给Main组件
          handleUpdateById={this.handleUpdateById}
          // 4.2 通过子传父技术，将回调函数传给Main组件
          handleDelById={this.handleDelById}
          // 14.2 通过父传子技术，将isAll传给Main组件
          isAll={isAll}
          // 15.2 子传父，将回调函数，传给Main组件
          handleCheckAll={this.handleCheckAll}
        ></Main>
        {/* 底部 */}
        <Footer
          // 5.2 通过父传子，把type传给Footer组件
          type={type}
          // 6.2 子传父，将回调函数传给Footer组件
          handleUpdateType={this.handleUpdateType}
          // 8.2 通过子传父，传回调函数给Footer组
          handleClearDone={this.handleClearDone}
          //  9.2 将list通过父传子传到Footer中
          list={list}
        ></Footer>
      </section>
    );
  }
}

class Header extends React.Component {
  // 🔔在React中收集用户数据，使用受控组件
  // 10.1 在Header组件中声明state.task
  state = {
    task: '',
  };

  // 11.3 监听回车事件，
  handleKeyDown = (e) => {
    const { handleAdd } = this.props;
    // 12.1 esc支持清除内容
    if (e.key === 'Escape') {
      this.setState({ task: '' });
      return;
    }

    if (e.key === 'Enter') {
      // 12.3 非空判断，提示用户不允许输入纯空格字符串
      if (!this.state.task.trim()) {
        alert('任务不能为空');
        return;
      }

      // 11.4 回车事件中触发回调
      handleAdd(this.state.task);
      // 12.2 新增之后清除输入框
      this.setState({ task: '' });
    }
  };

  render() {
    const { task } = this.state;
    return (
      <header className="header">
        <h1>todos</h1>
        <input
          // 10.2 state控制value
          value={task}
          // 10.3 onChange和setState更新数据
          onChange={(e) => this.setState({ task: e.target.value })}
          onKeyDown={this.handleKeyDown}
          className="new-todo"
          placeholder="需要做什么"
          autoFocus
        />
      </header>
    );
  }
}

class Main extends React.Component {
  render() {
    const { list, handleUpdateById, handleDelById, isAll, handleCheckAll } = this.props;
    return (
      <section className="main">
        <input
          // 14.3 将isAll控制全选按钮的checked属性
          checked={isAll}
          id="toggle-all"
          className="toggle-all"
          type="checkbox"
          // 15.3 子组件调用回调函数
          onChange={handleCheckAll}
        />
        <label htmlFor="toggle-all">全选</label>
        <ul className="todo-list">
          {/* // 2.3 在Main组件中，通过列表渲染生成多个任务 */}
          {list.map((item) => {
            return (
              // 🔔 注意加上key
              // 2.4 设置选中状态和样式
              <li className={item.isDone ? 'completed' : ''} key={item.id}>
                <div className="view">
                  <input
                    // 3.3 在Main组件中，onChange时调用回调函数，并且传参id
                    // 🗝️ 传id
                    onChange={() => handleUpdateById(item.id)}
                    className="toggle"
                    type="checkbox"
                    checked={item.isDone}
                  />
                  <label>{item.task}</label>
                  {/* 4.3 子组件内调用回调函数，并且传参id,  🗝️ 传id */}
                  <button onClick={() => handleDelById(item.id)} className="destroy"></button>
                </div>
              </li>
            );
          })}
        </ul>
      </section>
    );
  }
}
//  9.1 将Footer组件改造为函数组件
function Footer({ type, handleUpdateType, handleClearDone, list }) {
  // 9.3 在Footer中定义计算属性restLength
  // setState会组件刷新，🗝️ props改变也会导致组件更新

  // 🗝️在return同级定义的变量，会被重新计算，可以模拟计算属性
  const restLength = list.filter((item) => {
    return !item.isDone;
  }).length;

  return (
    <footer className="footer">
      <span className="todo-count">
        {/* //  9.4 使用插值显示剩余数量 */}
        <strong>{restLength}</strong> 剩余
      </span>
      <ul className="filters">
        <li>
          {/* 排它判断技术 */}
          {/* 当type为all时，加上selected */}
          <a
            // 5.3 通过比对type的值，给a标签加上className
            // 6.3 点击事件触发回调函数，并且传参type
            onClick={() => handleUpdateType('all')}
            className={type === 'all' ? 'selected' : ''}
            href="#/"
          >
            全部
          </a>
        </li>
        <li>
          {/* 当type为active时，加上selected */}
          <a
            // 6.3 点击事件触发回调函数，并且传参type
            onClick={() => handleUpdateType('active')}
            className={type === 'active' ? 'selected' : ''}
            href="#/active"
          >
            未完成
          </a>
        </li>
        <li>
          {/* 当type为completed时，加上selected */}
          <a
            // 6.3 点击事件触发回调函数，并且传参type
            onClick={() => handleUpdateType('completed')}
            className={type === 'completed' ? 'selected' : ''}
            href="#/completed"
          >
            已完成
          </a>
        </li>
      </ul>
      <button
        className="clear-completed"
        // 8.3 Footer中触发回调函数
        onClick={handleClearDone}
      >
        清除已完成
      </button>
    </footer>
  );
}
